/*******************************************************
> Copyright (C) 2024 ==iot== All rights reserved.
> File Name: heart_beat.c
> Author: wyf
> Created Time: 2024年08月26日 星期一 15时16分27秒
***************************************************/
#include"heart_beat.h"
// 定义互斥锁，确保更新和检查心跳时间时不会产生竞态条件
extern pthread_mutex_t heartbeat_lock;

// 记录客户端信息的数组
extern struct client_info clients[10];


//初始化客户端信息
void init_client_info() {
	for (int i = 0; i < 10; i++) {
		clients[i].fd = -1;
		clients[i].last_heartbeat = 0;
	}
}


// 更新客户端心跳时间
void update_client_heartbeat(int fd) {
	pthread_mutex_lock(&heartbeat_lock); // 加锁，防止竞态条件
	for (int i = 0; i < 10; i++) {
		if (clients[i].fd == fd) {
			clients[i].last_heartbeat = time(NULL); // 更新心跳时间
			break;
		}
	}
	pthread_mutex_unlock(&heartbeat_lock); // 解锁
}

// 处理客户端消息，确保所有收到的数据都更新心跳时间
void handle_client_message(int listenfd, char* buf) {
	if (strstr(buf, "\"type\":\"heartbeat\"") != NULL) {
		update_client_heartbeat(listenfd); // 如果是心跳包，更新心跳时间
	}
	else {
		update_client_heartbeat(listenfd); // 无论什么数据，更新心跳时间
	}
}

// 线程函数：定期发送心跳包并检查客户端超时
void* send_heartbeat(void* arg) {
	char timeout_msg[1024] = { 0 };
	strcpy(timeout_msg, "{\"type\":\"timeout\",\"message\":\"您已超时，服务器将关闭连接。\"}");//发送给客户端JSON，已经超时结束!!!
	int epollfd = *(int*)arg;
	int ret = 0;

	while (1) {
		sleep(1); // 每秒检测一次
		time_t now = time(NULL);

		pthread_mutex_lock(&heartbeat_lock); // 加锁，防止竞态条件
		for (int i = 0; i < 10; i++) {
			if (clients[i].fd != -1 && now - clients[i].last_heartbeat > 15) {
				printf("客户端%d超时，关闭连接\n", clients[i].fd);

				// 发送超时消息给客户端
				ret = send(clients[i].fd, timeout_msg, strlen(timeout_msg), 0);
				if (ret == -1) {
					perror("send");
				}

				// 关闭连接
				epoll_ctl(epollfd, EPOLL_CTL_DEL, clients[i].fd, NULL);
				close(clients[i].fd);
				remove_client(clients[i].fd);
			}
		}
		pthread_mutex_unlock(&heartbeat_lock); // 解锁
	}
	return NULL;
}


// 移除客户端信息
void remove_client(int fd) {
	for (int i = 0; i < 10; i++) {
		if (clients[i].fd == fd) {
			clients[i].fd = -1;
			break;
		}
	}
}


